#include <stdio.h>
#include <iostream>
#include <string>

#include "ServerBootstrap.h"
#include "ReactorThreadPool.h"
#include "Log.h"

using namespace dsth;
using std::string;

class EchoServer {
public:
    EchoServer(EventLoop* loop, const InetSocketAddress& addr)
        :  server_(loop, addr) {
        server_.SetOnConnection(std::make_pair(this, &EchoServer::OnConnect));
        server_.SetOnMessage(std::make_pair(this, &EchoServer::OnMessage));
    }

    EchoServer(ReactorThreadPool* pool, const InetSocketAddress& addr)
        : server_(pool, addr) {
        server_.SetOnConnection(std::make_pair(this, &EchoServer::OnConnect));
        server_.SetOnMessage(std::make_pair(this, &EchoServer::OnMessage));
    }

    void Run() {
        server_.Run();
    }

    void OnConnect(Connection* conn) {
        printf("An new connection\n");
    }

    void OnMessage(Connection* conn, ChannelBuffer* buf, Timestamp time) {
        string msg(buf->FetchAsString());
        printf("RECV:%s\n AT:%s\n\n", msg.c_str(), time.ToFomattedString().c_str());
        conn->Send(msg.c_str(), msg.length());
    }

private:
    ServerBootstrap server_;
};

#ifdef IS_WINDOWS
static void ExitForWindows() {
    printf("::WSACleanup()\n");
    ::WSACleanup();
}
#endif

static void promptForQuit() {
    std::string line;
    while (std::getline(std::cin, line)) {
        if (line[0] == 'q') {
            break;
        }
    }
}

int main(int argc, char** argv) {
    NewLogger("./multi_server.log", Logger::E_DEBUG);
#ifdef IS_WINDOWS
    WSADATA wsaData;
    int err = ::WSAStartup( MAKEWORD(2,2), &wsaData );
    if( err != NO_ERROR )
        printf("Error at WSAStartup\n");
    ::atexit(ExitForWindows);
#endif
    int start_type = 0;
    int thread_num = 1;
    if (argc > 1) {
        start_type = ::atoi(argv[1]);
        if (argc > 2) {
            int num = ::atoi(argv[2]);
            thread_num = (thread_num > num) ? thread_num : num;
        }
    }
    if (start_type == 0) {
        EventLoop loop;
        InetSocketAddress addr(2012);
        EchoServer echo(&loop, addr);
        echo.Run();

        InetSocketAddress addr2(2013);
        EchoServer echo2(&loop, addr2);
        echo2.Run();

        InetSocketAddress addr3(2014);
        EchoServer echo3(&loop, addr3);
        echo3.Run();

        loop.Loop();
    }
    else if (start_type == 1) {
        ReactorThread thread;
        EventLoop* loop = thread.Run();
        InetSocketAddress addr(2012);
        EchoServer echo(loop, addr);
        echo.Run();

        InetSocketAddress addr2(2013);
        EchoServer echo2(loop, addr2);
        echo2.Run();

        InetSocketAddress addr3(2014);
        EchoServer echo3(loop, addr3);
        echo3.Run();

        promptForQuit();
    }
    else {
        ReactorThreadPool pool(thread_num);
        InetSocketAddress addr(2012);
        EchoServer echo(&pool, addr);
        echo.Run();

        InetSocketAddress addr2(2013);
        EchoServer echo2(&pool, addr2);
        echo2.Run();

        InetSocketAddress addr3(2014);
        EchoServer echo3(&pool, addr3);
        echo3.Run();

        pool.Run();
        promptForQuit();
    }
    return 0;
}
